#ifndef PDTFUNCDEC_H
#define PDTFUNCDEC_H
#include <string>
#include <vector>
#include <assert.h>
#include "PDTVar.h"
#include "PDTListOfStatements.h"
#include "PDTCodeGraph.h"
#include "PDTExp.h"
#include "PDTStatement.h"
#include "PDTNumVar.h"
#include "PDTBoolVar.h"
#include "PDTAssign.h"
#include <stack>

class PDTFunctionDec :  public PDTNode, public TraverseIfc <PDTFunctionDec, PDTNode> {
public:  
    TRAVERSAL_IFC_IMPL(PDTFunctionDec)
private:
	unsigned int argc;
public:
	PDTFunctionDec(PDTCodeGraph &CG, string &name, 
            PDTListOfStatements & body,
			PDTVar * retVar, vector<PDTVar*> &arguments);

	string name;

	NodeTypeEnum getType() {
		return PDTFunctionDec_Em;
	}

	virtual PDTNode* clone(PDTCodeGraph& CG);
	virtual stringstream & toString(stringstream & ss) const;

	virtual const string & getName() const {
		return name;
	}

	PDTListOfStatements * getStatements() const 
	{
		int size = children.size();
		return dynamic_cast<PDTListOfStatements*> (children[size - 2]);
	}

	virtual PDTVar * getReturnVar() const {
		int size = children.size();
		return dynamic_cast<PDTVar*> (children[size - 1]);
	}

	virtual unsigned int getArgumentCount() const {
		return argc;
	}

    virtual PDTVar * getArgument(unsigned int i) const {
        assert( i < argc);
        return dynamic_cast<PDTVar*> (children[i]);
    }

	virtual bool isFunctionDec() {
		return true;
	}

	virtual bool eval(PDTCodeGraph &CG)
	{
		if (!(getStatements()->eval(CG)))
			return false;
		return true;
	}
};

class PDTFunctionCall :  public PDTExpBool, TraverseIfc <PDTFunctionCall, PDTNode> 
{ public:  TRAVERSAL_IFC_IMPL(PDTFunctionCall)
private:
	string name; // function name
	PDTFunctionDec * func_ptr;
	unsigned int argc;
//	PDTVar * retVar; // TODO: handle return value

public:
	PDTFunctionCall(PDTCodeGraph & CG, vector<PDTNode*> & arguments,
			string & aName, PDTFunctionDec * aFunc);

	PDTFunctionCall(PDTCodeGraph & CG, string & aName, PDTFunctionDec * aFunc);

	NodeTypeEnum getType() {
		return PDTFunctionCall_Em;
	}

	PDTFunctionDec* getFuncPtr() const {
		return func_ptr;
	}

	virtual unsigned int getArgumentCount() const {
		return argc;
	}

    virtual PDTNode * getArgument(unsigned int i) const {
        assert( i < argc);
        return children[i];
    }

//	void fixReturnVariable(PDTCodeGraph & CG);

	void setFunctionDec(PDTFunctionDec * aFunc, PDTCodeGraph & CG) {
		func_ptr = aFunc;
//		fixReturnVariable(CG);
	}

	bool isInitialized() {
		return (func_ptr == NULL);
	}
    virtual bool isNum() ;

	virtual bool isBool();

	string getName() {
		return name;
	}
    bool isSpecial () const {
        return isSpecial(name);
    }

	virtual bool isFunctionCall() {
		return true;
	}

	virtual bool eval(PDTCodeGraph& CG);

	virtual PDTNode* clone(PDTCodeGraph& CG);

	virtual stringstream & toString(stringstream & ss) const ;

	bool checkConsistency(string & msg);
    static bool isSpecial(const string & fname);
};

bool checkVars(PDTVar * v1, PDTVar * v2);

#endif // PDTFUNCDEC_H
